package com.turing.post.antimoney.impl;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.ejb.EJB;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;

import com.turing.post.antimoney.util.SuspiciousReport;
import com.turing.post.antimoney.util.SuspiciousReportBusiness;
import com.turing.post.antimoney.util.SuspiciousReportDao;
import com.turing.post.antimoney.util.SuspiciousTrans;
import com.turing.post.antimoney.util.SuspiciousTransDao;
import com.turing.post.common.util.PCPSCommonDao;
import com.turing.post.common.util.SysOperLog;
import com.turing.post.common.util.SysOperLogDao;
import com.turing.post.organization.util.IssueCompany;
import com.turing.post.organization.util.IssueCompanyDao;
import com.turing.post.organization.util.OrganApplicationException;
import com.turing.post.organization.util.OrganRespCode;
import com.turing.post.report.util.BinaryFileInfo;
import com.turing.post.report.util.BinaryFileInfoDao;
import com.turing.post.util.PCPSApplicationException;
import com.turing.post.util.PCPSUtil;
import com.turing.post.util.PCPSWebInput;

/**
 * @author zxp
 * @Mar 27, 2013
 */
@Stateless(mappedName = "antimoney.impl.SuspiciousReportBusinessImpl")
@Remote
@Local
public class SuspiciousReportBusinessImpl implements SuspiciousReportBusiness {

	@EJB(mappedName = "antimoney.impl.SuspiciousReportDaoImpl")
	private SuspiciousReportDao suspiciousReportDaoImpl;

	@EJB(mappedName = "common.impl.PCPSCommonDaoImpl")
	private PCPSCommonDao commonDaoImpl;

	@EJB(mappedName = "organization.impl.IssueCompanyDaoImpl")
	private IssueCompanyDao issueCompanyDaoImpl;

	@EJB(mappedName = "antimoney.impl.SuspiciousTransDaoImpl")
	private SuspiciousTransDao suspiciousTransDaoImpl;
	@EJB(mappedName = "report.impl.BinaryFileInfoDaoImpl")
	private BinaryFileInfoDao binaryFileInfoDaoImpl;

	@EJB(mappedName = "common.impl.SysOperLogDaoImpl")
	private SysOperLogDao sysOperLogDaoImpl;
	private void errException(String error) throws PCPSApplicationException {
		throw new PCPSApplicationException(
				PCPSApplicationException.ERRCODE_CATEGORY_APPLICATION,
				"SuspiciousReport", error);
	}

	@Override
	public void createSuspiciousReport(PCPSWebInput webInput,
			List<BigInteger> alarmInfoIds, SuspiciousReport sr)
			throws PCPSApplicationException {
		if (webInput == null || PCPSUtil.isEmpty(webInput.getOperBranchNo())) {
			errException("操作人员为空!");
		}
		String issueCompanyNo = PCPSUtil.getIssueCompanyNo(webInput);
		IssueCompany ic = issueCompanyDaoImpl
				.getIssueCompanyByIssueCompanyNo(issueCompanyNo);
		if (PCPSUtil.isEmpty(ic.getRINM()) || PCPSUtil.isEmpty(ic.getFIRC())
				|| PCPSUtil.isEmpty(ic.getFICD())) {
			errException("报告机构名称、所在地区编码、分支机构/网点代码不可为空!");
		}
		SuspiciousReport insertSr = getSuspiciousReport(ic, sr);
		BigInteger alarmInfoId = null;
		List<SuspiciousTrans> stList = new ArrayList<SuspiciousTrans>();
		Integer SCTN_ALL = 0;
		Integer TTNM_ALL = 0;

		// 生成XML文件
		BigInteger repositBinaryId = BigInteger.ZERO;
		BigInteger reportId = commonDaoImpl.getUniqueIntegerKey();
		insertSr.setIssueCompanyNo(issueCompanyNo);
		insertSr.setReportId(reportId);
		insertSr.setRepositBinaryId(repositBinaryId);
		List<ByteArrayOutputStream> xmlBos = new ArrayList<ByteArrayOutputStream>();
		// 根据预警信息id查询可疑交易
		for (int i = 0; i < alarmInfoIds.size(); i++) {
			alarmInfoId = alarmInfoIds.get(i);
			stList = suspiciousTransDaoImpl
					.getSuspiciousTransListByAlarmInfoId(alarmInfoId);
			SCTN_ALL = stList.size();
			TTNM_ALL = stList.size();
			insertSr.setSCTN(SCTN_ALL);// 可疑主体数量
			insertSr.setTTNM(TTNM_ALL);// 可疑交易数量
			xmlBos = generateReportXMLFile(ic, insertSr, stList);
		}
		// 保存上报文件
		BinaryFileInfo bf = new BinaryFileInfo();
		BigInteger bfId = binaryFileInfoDaoImpl.getUniqueBinaryFileKey();
		bf.setFileId(bfId);
		bf.setFileType("zip");
		ByteArrayOutputStream zipBos = new ByteArrayOutputStream();
		for (int i = 1; i <= xmlBos.size(); i++) {
			ByteArrayOutputStream bos = xmlBos.get(i - 1);
			String xmlFileName = insertSr.getORXN() + "-"
					+ String.format("%04d", i);
			try {
				ZipOutputStream out = new ZipOutputStream(zipBos);
				out.setMethod(ZipOutputStream.DEFLATED);
				ZipEntry ze = new ZipEntry(xmlFileName + ".xml");
				ze.setMethod(ZipEntry.DEFLATED);
				out.putNextEntry(ze);
				ByteArrayInputStream bis = new ByteArrayInputStream(bos
						.toByteArray());
				byte[] buf = new byte[1024];
				int count;
				while ((count = bis.read(buf, 0, buf.length)) != -1) {
					out.write(buf, 0, count);
				}
				out.flush();
				out.closeEntry();
				out.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		byte[] zipFile = zipBos.toByteArray();
		bf.setFileLength(zipFile.length);
		bf.setFileName(insertSr.getORXN());
		bf.setFileContent(zipFile);
		binaryFileInfoDaoImpl.insertBinaryFileInfo(bf);
		// 插入Report记录
		insertSr.setRepositBinaryId(bfId);
		suspiciousReportDaoImpl.insert(insertSr);
		// 修改可疑交易明细
		for (SuspiciousTrans st : stList) {
			SuspiciousTrans id = new SuspiciousTrans();
			id.setAlarmInfoId(st.getAlarmInfoId());
			id.setSeqNo(st.getSeqNo());
			SuspiciousTrans updateSt = suspiciousTransDaoImpl
					.getSuspiciousTransById(id);
			updateSt.setReportId(reportId);
			suspiciousTransDaoImpl.updateSuspiciousTrans(updateSt);
		}

		// 日志记录
		sysOperLogDaoImpl.insertSysOperLogInfo(webInput,
				SysOperLog.operType_Add, "可疑交易打包上报", "ReportId:"+insertSr.getReportId());
	}

	/**
	 * 生成上报文件
	 */
	private List<ByteArrayOutputStream> generateReportXMLFile(IssueCompany ic,
			SuspiciousReport report, List<SuspiciousTrans> stList) {
		List<ByteArrayOutputStream> xmlBos = new ArrayList<ByteArrayOutputStream>();
		Element root = new Element("PSTR");
		Document document = new Document(root);
		Element RBIF = new Element("RBIF");
		RBIF.addContent(new Element("RINM").setText(dealNull(ic.getRINM())));// 报告机构名称
		RBIF.addContent(new Element("FIRC").setText(dealNull(ic.getFIRC())));// 报告机构所在地区编码
		RBIF.addContent(new Element("FICD").setText(dealNull(ic.getFICD())));// 报告机构分支机构/网点代码
		RBIF.addContent(new Element("RFSG").setText(dealNull(report.getRFSG().toString())));// 报送次数标志
		RBIF.addContent(new Element("ORXN").setText(dealNull(report.getORXN())));// 初次报送的可疑交易报文名称
		RBIF.addContent(new Element("SSTM").setText(dealNull(report.getSSTM())));// 可疑交易（行为）处理情况
		RBIF.addContent(new Element("STCR").setText(dealNull(report.getSTCR())));// 可疑交易（行为）特征
		RBIF.addContent(new Element("SSDS").setText(dealNull(report.getSSDS())));// 可疑交易（行为）描述
		RBIF.addContent(new Element("UDSI").setText(dealNull(report.getUDSI())));// 机构自定可疑交易标准编号
		RBIF.addContent(new Element("SCTN").setText(dealNull(report.getSCTN().toString())));// 可疑主体数量
		RBIF.addContent(new Element("TTNM").setText(dealNull(report.getTTNM().toString())));// 可疑交易数量
		root.addContent(RBIF);
		Element CTIFs = new Element("CTIFs");
		Element STIFs = new Element("STIFs");
		for (int i = 1; i <= stList.size(); i++) {
			SuspiciousTrans st = stList.get(i - 1);
			Element CTIF = new Element("CTIF").setAttribute("seqno", i + "");
			CTIF.addContent(new Element("CTNM").setText(dealNull(st.getCTNM())));// 可疑主体姓名/名称
			CTIF.addContent(new Element("SMID").setText(dealNull(st.getSMID())));// 主体特约商户编号
			CTIF.addContent(new Element("CITP").setText(dealNull(st.getCITP())));// 可疑主体身份证件/证明文件类型
			CTIF.addContent(new Element("CTID").setText(dealNull(st.getCTID())));// 可疑主体身份证件/证明文件号码
			Element CCIF = new Element("CCIF");
			Element CTAR = new Element("CTAR");
			CTAR.setText(dealNull(st.getCTAR()));
			CCIF.addContent(CTAR);// 详细住址
			CCIF.addContent(new Element("CCTL").setText(dealNull(st.getCCTL())));// 联系电话
			CCIF.addContent(new Element("CEML").setText(dealNull(st.getCEML())));// 电子邮件
			CTIF.addContent(CCIF);
			CTIF.addContent(new Element("CTVC").setText(dealNull(st.getCTVC())));// 可疑主体的职业/行业类别
			CTIF.addContent(new Element("CRNM").setText(dealNull(st.getCRNM())));// 可疑主体的法定代表人姓名
			CTIF.addContent(new Element("CRIT").setText(dealNull(st.getCRIT())));// 可疑主体的法定代表人身份证件类型
			CTIF.addContent(new Element("CRID").setText(dealNull(st.getCRID())));// 可疑主体的法定代表人身份证件号码
			CTIFs.addContent(CTIF);

			Element STIF = new Element("STIF").setAttribute("seqno", i + "");
			STIF.addContent(new Element("CTNM").setText(dealNull(st.getCTNM())));// 可疑主体姓名/名称
			STIF.addContent(new Element("CITP").setText(dealNull(st.getCITP())));// 可疑主体身份证件/证明文件类型
			STIF.addContent(new Element("CTID").setText(dealNull(st.getCTID())));// 可疑主体身份证件/证明文件号码
			STIF.addContent(new Element("CBAT").setText(dealNull(st.getCBAT())));// 可疑主体的银行账号种类
			STIF.addContent(new Element("CBAC").setText(dealNull(st.getCBAC())));// 可疑主体的银行账号
			STIF.addContent(new Element("CABM").setText(dealNull(st.getCABM())));// 可疑主体银行账号的开户银行名称
			STIF.addContent(new Element("CTAT").setText(dealNull(st.getCTAT())));// 可疑主体的支付账户种类
			STIF.addContent(new Element("CTAC").setText(dealNull(st.getCTAC())));// 可疑主体的支付账户账号
			STIF.addContent(new Element("CPIN").setText(dealNull(st.getCPIN())));// 可疑主体所在支付机构的名称
			STIF.addContent(new Element("CPBA").setText(dealNull(st.getCPBA())));// 可疑主体所在支付机构的银行账号
			STIF.addContent(new Element("CPBN").setText(dealNull(st.getCPBN())));// 可疑主体所在支付机构的银行账号的开户银行名称
			STIF.addContent(new Element("CTIP").setText(dealNull(st.getCTIP())));// 可疑主体的交易IP地址
			String TSTM = "";
			if (null != st.getTSTM()) {
				PCPSUtil.getStringYMDHMSPackedByDate(st.getTSTM());
			}
			STIF.addContent(new Element("TSTM").setText(dealNull(TSTM)));// 交易时间
			STIF.addContent(new Element("CTTP").setText(dealNull(st.getCTTP())));// 货币资金转移方式
			STIF.addContent(new Element("TSDR").setText(dealNull(st.getTSDR())));// 资金收付标志
			STIF.addContent(new Element("CRPP").setText(dealNull(st.getCRPP())));// 资金用途
			STIF.addContent(new Element("CRTP").setText(dealNull(st.getCRTP())));// 交易币种
			String CRAT;
			CRAT = null == st.getCRAT() ? "" : st.getCRAT().toString();
			STIF.addContent(new Element("CRAT").setText(dealNull(CRAT)));// 交易金额
			STIF.addContent(new Element("TCNM").setText(dealNull(st.getTCNM())));// 交易对手姓名/名称
			STIF.addContent(new Element("TSMI").setText(dealNull(st.getTSMI())));// 交易对手特约商户编号
			STIF.addContent(new Element("TCIT").setText(dealNull(st.getTCIT())));// 交易对手证件/证明文件类型
			STIF.addContent(new Element("TCID").setText(dealNull(st.getTCID())));// 交易对手证件/证明文件号码
			STIF.addContent(new Element("TCAT").setText(dealNull(st.getTCAT())));// 交易对手的银行账号种类
			STIF.addContent(new Element("TCBA").setText(dealNull(st.getTCBA())));// 交易对手的银行账号
			STIF.addContent(new Element("TCBN").setText(dealNull(st.getTCBN())));// 交易对手银行账号的开户银行名称
			STIF.addContent(new Element("TCTT").setText(dealNull(st.getTCTT())));// 交易对手的支付账户种类
			STIF.addContent(new Element("TCTA").setText(dealNull(st.getTCTA())));// 交易对手的支付账户号码
			STIF.addContent(new Element("TCPN").setText(dealNull(st.getTCPN())));// 交易对手所在支付机构的名称
			STIF.addContent(new Element("TCPA").setText(dealNull(st.getTCPA())));// 交易对手所在支付机构的银行账号
			STIF.addContent(new Element("TPBN").setText(dealNull(st.getTPBN())));// 交易对手所在支付机构银行账号的开户银行名称
			STIF.addContent(new Element("TCIP").setText(dealNull(st.getTCIP())));// 交易对手的交易IP地址
			STIF.addContent(new Element("TMNM").setText(dealNull(st.getTMNM())));// 交易商品名称
			STIF.addContent(new Element("BPTC").setText(dealNull(st.getBPTC())));// 银行与支付机构之间的业务交易编码
			STIF.addContent(new Element("PMTC").setText(dealNull(st.getPMTC())));// 支付机构与商户之间的业务交易编码
			STIF.addContent(new Element("TICD").setText(dealNull(st.getTICD())));// 业务标识号
			STIFs.addContent(STIF);
		}
		root.addContent(CTIFs);
		root.addContent(STIFs);
		try {
			Format format = Format.getPrettyFormat();
			format.setEncoding("gb18030");
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			XMLOutputter XMLOut = new XMLOutputter(format);
			XMLOut.output(document, bos);
			xmlBos.add(bos);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return xmlBos;
	}

	private String dealNull(String str) {
		if (PCPSUtil.isEmpty(str)) {
			return "@I";
		} else {
			return str;
		}
	}

	// IssueCompany表字段
	// RINM 报告机构名称 Varchar(128) Null
	// FIRC 报告机构所在地区编码 char(6) Null 报告机构总部注册地的行政区划代码
	// FICD 报告机构分支机构/网点代码 Varchar(32) Null
	private SuspiciousReport getSuspiciousReport(IssueCompany ic,
			SuspiciousReport sr) throws PCPSApplicationException {
		if (PCPSUtil.isEmpty(sr.getSSTM()) || PCPSUtil.isEmpty(sr.getSTCR())
				|| PCPSUtil.isEmpty(sr.getSSDS())) {
			errException("可疑交易（行为）处理情况、（行为）特征、（行为）描述不可为空!");
		}
		Date reportDate = ic.getTranDate();
		sr.setReportDate(reportDate);
		String batchNo = suspiciousReportDaoImpl
				.getSuspiciousReportBatchNoByReportDate(PCPSUtil
						.getPackedYMDString2(sr.getReportDate()), ic
						.getIssueCompanyNo());
		sr.setBatchNo(batchNo);
		// SeqNo 顺序号 创建时默认1
		sr.setSeqNo(1);
		// RFSG 报送次数标志 创建时默认1
		sr.setRFSG(1);
		// ORXN 初次报送的可疑交易报文名称 报文类型和交易报告类型标识＋报告机构编码＋报送日期＋当日报送批次＋文件在该批次中的编号.XML
		String ORXN = "NPS" + ic.getFICD() + "-"
				+ PCPSUtil.getPackedYMDString(ic.getTranDate()) + "-" + batchNo;
		sr.setORXN(ORXN);
		sr.setReportDate(commonDaoImpl.getDatabaseSysTime());
		sr.setReportStatus("1");
		// UDSI 可疑交易（行为）所符合的报告机构自定可疑交易标准的编号，该编号应事先报备中国反洗钱监测分析中心
		sr.setUDSI("PCPS");
		return sr;
	}

	// ///////////////////////补充上报//////
	/**
	 * 补充上报可疑交易报告信息
	 * 
	 * @param reoprtid
	 * @throws PCPSApplicationException
	 */
	public void supplySuspiciousReport(PCPSWebInput webInput,
			BigInteger reoportid) throws PCPSApplicationException {
		// 登录用户机构号为空
		if (PCPSUtil.isEmpty(webInput.getOperBranchNo())) {
			throw new OrganApplicationException(
					OrganApplicationException.ERRCODE_CATEGORY_APPLICATION,
					OrganRespCode.ISSUE_INSERT_UPDATE, "登录用户机构号为NULL");
		}
		// 补充上报可疑交易报告id
		if (reoportid == null) {
			throw new OrganApplicationException(OrganRespCode.RC_ARGS_NULL, "",
					"上报可疑交易报告id为空!");
		}
		// 根据上报id和上报状态为：3检索可疑报告对象
		SuspiciousReport susreport = suspiciousReportDaoImpl
				.getSuspiciousReportByIdandStatus(webInput, reoportid,
						SuspiciousReport.REPORTSTATUS_FAILURE);
		if (susreport == null) {
			throw new OrganApplicationException(OrganRespCode.RC_ARGS_NULL, "",
					"上报可疑交易报告为空!");
		} else {
			IssueCompany ic = issueCompanyDaoImpl
					.getIssueCompanyByIssueCompanyNo(susreport
							.getIssueCompanyNo());
			List<SuspiciousTrans> sustranslist = suspiciousTransDaoImpl
					.getSuspiciousTransListByReportId(reoportid);
			if (sustranslist == null || sustranslist.size() == 0) {// 根据reportid检索支付机构可疑交易(行为)报告数据字典列表
				throw new OrganApplicationException(OrganRespCode.RC_ARGS_NULL,
						"", "支付机构可疑交易(行为)报告数据字典列表为空!");
			} else {
				BigInteger fileid = new BigInteger("0");
				String batchNo = suspiciousReportDaoImpl
						.getSuspiciousReportBatchNoByReportDate(PCPSUtil
								.getPackedYMDString2(ic.getTranDate()), ic
								.getIssueCompanyNo());
				susreport.setBatchNo(batchNo);
				// SeqNo 顺序号 创建时默认1
				susreport.setSeqNo(susreport.getSeqNo() + 1);
				// RFSG 报送次数标志 创建时默认1
				susreport.setRFSG(susreport.getRFSG() + 1);
				// ORXN 初次报送的可疑交易报文名称
				// 报文类型和交易报告类型标识＋报告机构编码＋报送日期＋当日报送批次＋文件在该批次中的编号.XML
				String ORXN = "RPS" + ic.getFICD() + "-"
						+ PCPSUtil.getPackedYMDString(ic.getTranDate()) + "-"
						+ batchNo;
				susreport.setORXN(ORXN);
				byte[] zipByte = new byte[1024];
				List<ByteArrayOutputStream> xmlBos = new ArrayList<ByteArrayOutputStream>();
				xmlBos = generateReportXMLFile(ic, susreport, sustranslist);
				ByteArrayOutputStream zipBos = new ByteArrayOutputStream();
				for (int i = 1; i <= xmlBos.size(); i++) {
					ByteArrayOutputStream bos = xmlBos.get(i - 1);
					String xmlFileName = susreport.getORXN() + "-"
							+ String.format("%04d", i);
					try {
						ZipOutputStream out = new ZipOutputStream(zipBos);
						out.setMethod(ZipOutputStream.DEFLATED);
						ZipEntry ze = new ZipEntry(xmlFileName + ".xml");
						ze.setMethod(ZipEntry.DEFLATED);
						out.putNextEntry(ze);
						ByteArrayInputStream bis = new ByteArrayInputStream(bos
								.toByteArray());
						byte[] buf = new byte[1024];
						int count;
						while ((count = bis.read(buf, 0, buf.length)) != -1) {
							out.write(buf, 0, count);
						}
						out.flush();
						out.closeEntry();
						out.close();
					} catch (FileNotFoundException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				zipByte = zipBos.toByteArray();
				// 根据文件ID检索文件资料表对象
				if (susreport.getRepositBinaryId() != null) {
					BinaryFileInfo binaryfileinfo = binaryFileInfoDaoImpl
							.getBinaryFileInfoById(susreport
									.getRepositBinaryId());
					if (binaryfileinfo != null) {// 更新
						fileid = susreport.getRepositBinaryId();
						binaryfileinfo.setFileContent(zipByte);
						binaryfileinfo.setFileName(susreport.getORXN());
						binaryfileinfo.setBackFile(null);
						binaryfileinfo.setBackFileName(null);
						binaryFileInfoDaoImpl
								.updateBinaryFileInfo(binaryfileinfo);
					} else {// 新创建
						BinaryFileInfo newbinaryfileinfo = new BinaryFileInfo();
						fileid = binaryFileInfoDaoImpl.getUniqueBinaryFileKey();
						newbinaryfileinfo.setFileId(fileid);
						newbinaryfileinfo.setFileContent(zipByte);
						newbinaryfileinfo.setFileLength(zipByte.length);
						newbinaryfileinfo.setFileType("zip");
						newbinaryfileinfo.setFileName(susreport.getORXN());
						binaryFileInfoDaoImpl
								.insertBinaryFileInfo(newbinaryfileinfo);
					}
				} else {// 新创建
					BinaryFileInfo newbinaryfileinfo = new BinaryFileInfo();
					fileid = binaryFileInfoDaoImpl.getUniqueBinaryFileKey();
					newbinaryfileinfo.setFileId(fileid);
					newbinaryfileinfo.setFileContent(zipByte);
					newbinaryfileinfo.setFileLength(zipByte.length);
					newbinaryfileinfo.setFileType("zip");
					newbinaryfileinfo.setFileName(susreport.getORXN());
					binaryFileInfoDaoImpl
							.insertBinaryFileInfo(newbinaryfileinfo);
				}
				// 更新可疑交易报告表（SuspiciousReport）
				susreport.setRepositBinaryId(fileid);
				susreport
						.setReportStatus(SuspiciousReport.REPORTSTATUS_REPORTING);
				suspiciousReportDaoImpl.updateSuspiciousReport(susreport);
			}
		}
	}
}
